package com.zian.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zian.common.CommonConstant;
import com.zian.context.BaseContext;
import com.zian.domain.dto.LoginDTO;
import com.zian.domain.dto.PageDTO;
import com.zian.domain.dto.UpdateAdminDTO;
import com.zian.domain.dto.UpdatePwdDTO;
import com.zian.domain.po.SysAdminUser;
import com.zian.domain.query.UserQuery;
import com.zian.domain.vo.UserQueryVO;
import com.zian.enums.IsDeletedEnum;
import com.zian.enums.LockedEnum;
import com.zian.exception.BadRequestException;
import com.zian.exception.BizIllegalException;
import com.zian.exception.DbException;
import com.zian.mapper.SysAdminUserMapper;
import com.zian.properties.JwtProperties;
import com.zian.service.ISysAdminUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zian.utils.IdUtils;
import com.zian.utils.JwtUtil;
import com.zian.utils.Md5Utils;
import com.zian.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author
 * @since 2024-09-08
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysAdminUserServiceImpl extends ServiceImpl<SysAdminUserMapper, SysAdminUser> implements ISysAdminUserService {

    private final JwtUtil jwtUtil;

    private final RedisUtils redisUtils;

    private final JwtProperties jwtProperties;

    @Override
    public void updateLocked(Long id) {
        // 1.校验参数
        if (id == null) throw new BadRequestException("请选择要操作的员工");
        SysAdminUser adminUser = getById(id);
        adminUser.setLocked(adminUser.getLocked().equals(LockedEnum.LOCKED) ? LockedEnum.UNLOCKED : LockedEnum.LOCKED);
        // 2. 修改用状态
        boolean b = lambdaUpdate()
                .eq(SysAdminUser::getId, id)
                .set(SysAdminUser::getLocked, adminUser.getLocked())
                .set(SysAdminUser::getUpdateTime, LocalDateTime.now())
                .update();
        if (!b) throw new DbException("更新失败");
    }

    /**
     * 批量删除员工
     *
     * @param ids
     */
    @Override
    public void deleteAdminById(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) throw new BadRequestException("请选择要删除的员工");
        // 逻辑删除
        lambdaUpdate()
                .in(SysAdminUser::getId, ids)
                .set(SysAdminUser::getIsDeleted, IsDeletedEnum.YES)
                .set(SysAdminUser::getUpdateTime, LocalDateTime.now())
                .update();

    }

    @Override
    public void addAdmin(UpdateAdminDTO dto) {
        SysAdminUser adminUser = BeanUtil.toBean(dto, SysAdminUser.class);
        SysAdminUser one = getBaseMapper().getAdminById(dto.getUsername());
        if (one != null) throw new BadRequestException("用户名已存在");
        adminUser.setPassword(Md5Utils.encrypt(dto.getPassword()));
        adminUser.setLocked(LockedEnum.UNLOCKED);
        adminUser.setIsDeleted(IsDeletedEnum.NO);
        log.info("新增管理员数据：{}", adminUser);
        boolean b = save(adminUser);
        if (!b) throw new DbException("新增失败");
    }

    @Override
    public void updatePwd(UpdatePwdDTO dto) {
        Long currentId = BaseContext.getCurrentId();
        SysAdminUser adminUser = getById(currentId);
        // 数据库密码是否匹配
        if (!Md5Utils.verify(dto.getOldPassword(), adminUser.getPassword())) {
            throw new BadRequestException("旧密码不正确");
        }

        // 更新密码
        adminUser.setPassword(Md5Utils.encrypt(dto.getNewPassword()));
        adminUser.setUpdateTime(null);
        boolean b = updateById(adminUser);
        if (!b) throw new DbException("更新失败");

    }

    @Override
    public PageDTO<UserQueryVO> queryPage(UserQuery query) {
        Page<SysAdminUser> page = query.toMpPageDefaultSortByCreateTimeDesc();
        lambdaQuery()
                .like(StrUtil.isNotBlank(query.getUsername()), SysAdminUser::getUsername, query.getUsername())
                .eq(query.getGender() != null, SysAdminUser::getGender, query.getGender())
                .eq(query.getLocked() != null, SysAdminUser::getLocked, query.getLocked())
                .page(page);
        if (CollUtil.isEmpty(page.getRecords())) return PageDTO.empty(page);

        return PageDTO.of(page, UserQueryVO.class);
    }

    @Override
    public void logout(String token) {
        if (StrUtil.isBlank(token)) return;
        // 清除缓存中的token 和 RefreshToken

        Long currentId = BaseContext.getCurrentId();
        Serializable cacheObject = redisUtils.getCacheObject(CommonConstant.LOGIN_ADMIN_USERID_KEY + currentId);
        if (cacheObject != null){
            // 删除token
            String key =CommonConstant.LOGIN_ADMIN_USER_KEY + (String) cacheObject;
            redisUtils.deleteObject(key);
        }

        // 删除 userId
        redisUtils.deleteObject(CommonConstant.LOGIN_ADMIN_USERID_KEY + currentId);


        BaseContext.removeCurrentId();

    }

    @Override
    public void updateInfo(UpdateAdminDTO dto) {
        Long userId = dto.getId() == null ? BaseContext.getCurrentId() : dto.getId();
        SysAdminUser adminUser = getById(userId);
        if (adminUser == null) throw new BizIllegalException("用户不存在");
        adminUser.setNickName(dto.getNickName());
        adminUser.setGender(dto.getGender());
        adminUser.setPhone(dto.getPhone());
        adminUser.setUpdateTime(null);
        adminUser.setAvatar(dto.getAvatar());
        boolean b = updateById(adminUser);
        if (!b) throw new DbException("更新失败");
    }

    @Override
    public String login(LoginDTO dto) {
        // 根据用户名查询
        SysAdminUser one = lambdaQuery().eq(SysAdminUser::getUsername, dto.getUsername()).one();
        if (one == null) throw new BadRequestException("用户名或密码错误");
        if (one.getIsDeleted().equals(IsDeletedEnum.YES)) throw new BadRequestException("用户不存在");
        if (one.getLocked().equals(LockedEnum.LOCKED)) throw new BadRequestException("用户已禁用");
        // 对密码进行加密
        boolean flag = Md5Utils.verify(dto.getPassword(), one.getPassword());
        if (!flag) throw new BadRequestException("用户名或密码错误");

        // 设置登录时间
        one.setExpireTime(new Date());
        String token = IdUtils.simpleUUID();

        // 1. token 作为key 用户信息作为 value 存储到 redis 中
        String key = CommonConstant.LOGIN_ADMIN_USER_KEY + token;
        redisUtils.setCacheObject(key, one, jwtProperties.getTtl().intValue(), TimeUnit.MINUTES);
        // 生成token
        String jwt = jwtUtil.createJWT(token);



        // 2. 用户id 作为key ， uuid 作为 value ，来实现单点登录
        String userIdKey = CommonConstant.LOGIN_ADMIN_USERID_KEY + one.getId();
        Serializable cacheObject = redisUtils.getCacheObject(userIdKey);

        //2.1 删除上一个用户的缓存信息
        if (cacheObject!=null){
            String cacheToken = (String) cacheObject;
            // 2.1. 删除 token 的缓存
            redisUtils.deleteObject(CommonConstant.LOGIN_ADMIN_USER_KEY + cacheToken);
            // 2.1. 删除 userId 的缓存
            redisUtils.deleteObject(userIdKey);
        }

        // 2.2. 用户id 作为key ， uuid 作为 value ，来实现单点登录
        redisUtils.setCacheObject(userIdKey, token, jwtProperties.getTtl().intValue(), TimeUnit.MINUTES);


        return jwt;
    }

    @Override
    public SysAdminUser getUserInfo(Long id) {
        Long userId = id == 0L ? BaseContext.getCurrentId() : id;
        SysAdminUser adminUser = getById(userId);
        if (adminUser == null) throw new BizIllegalException("用户不存在");
        return adminUser;
    }
}
